/**
 ******************************************************************************
 * @file	fpga-2016.h
 * @brief	fpga-2016 存储器通信

采用原始 fpga-2016 SPI通信协议


 *
 @section Platform
    -#
 @section Library
    -#
 *
 * @section Depend
 *	-# spi_mxs.ko
 *	-# spidev.ko

- 2016-12-14,MenglongWu,MenglongWoo@aliyun.com
*/

#ifndef _FPGA_TR700_H_
#define _FPGA_TR700_H_
// #include <autoconfig.h>
#include <stdbool.h>
#include <pthread.h>

#ifdef __cplusplus
extern "C" {
#endif

#define BIT_DEF       0x01
#define BIT_TX        0x02
#define BIT_RX        0x04
#define BIT_OTDR_DATA 0x08
#if CONFIG_USE_PRINTL
#define OTDR_DBG_LEVEL             (LEVEL_ID(LEVEL_GROUP - 1, SUB_GROUP - 1))
#define DBG_TX                     (OTDR_DBG_LEVEL & BIT_TX)
#define DBG_RX                     (OTDR_DBG_LEVEL & BIT_RX)
#define DBG_BIT_OTDR_DATA          (OTDR_DBG_LEVEL & BIT_OTDR_DATA)

#define EN_OTDR_DBG_LEVEL(en)      (OTDR_DBG_LEVEL |= (en))
#define DISABLE_OTDR_DBG_LEVEL(en) (PRINT_OTDR_DATA &= ~(en))
#elif CONFIG_USE_DEBUG_ENV
// extern int env_otdr_dbg_level;
// extern int env_print_otdr_data;
// extern int env_dbg_tx;
// extern int env_dbg_rx;
// extern int env_dbg_bit_otdr_data;
#define OTDR_DBG_LEVEL    env_otdr_dbg_level
#define PRINT_OTDR_DATA   env_print_otdr_data

#define DBG_TX            env_dbg_tx
#define DBG_RX            env_dbg_rx
#define DBG_BIT_OTDR_DATA env_dbg_bit_otdr_data

#define EN_OTDR_DBG_LEVEL(en)
#define EN_PRINT_OTDR_DATA(en)
#define EN_OTDR_PRINTL(en)
#else
#define OTDR_DBG_LEVEL    1
#define PRINT_OTDR_DATA   1

#define DBG_TX            1
#define DBG_RX            1
#define DBG_BIT_OTDR_DATA 1

#define EN_OTDR_DBG_LEVEL(en)
#define EN_PRINT_OTDR_DATA(en)
#define EN_OTDR_PRINTL(en)
#endif


#define OTDR_PULSE_ARRAY     (16)  // 脉冲开关编码16byte、128bit，为1时打开功率，0关闭


//*****************************************************************************
// FPGA所有项目用到的命令编号
//*****************************************************************************

/* OTDR 测试数据命令 */
#define OTDR_RETURN          (0xf0)  // 无用
#define OTDR_RESET           (0xe0)  // 无用

#define OTDR_PARAM           (0x10)  // OTDR 设置参数
#define OTDR_START           (0x11)  // 启动OTDR测试
#define OTDR_STOP            (0x12)  // 停止OTDR测试
#define OTDR_IS_FINISH       (0x13)  // 询问OTDR测试是否完成，这个东西最好作废，改成中断

#define OTDR_REDLASER        (0x14)  // 作废：FPGA控制红光

#define OTDR_ALIVE           (0xa0)  // 判断FPGA通信是否正常
#define OTDR_COM_LASER       (0x15)  // 是否存在通信光
#define OTDR_VER             (0xa1)  // 获取FPGA版本
#define OTDR_ROTDR           (0x20)  // 返回部分OTDR数据，数据长度根据具体型号而定
#define OTDR_APD_TEMP        (0x21)  // 读取APD温度，温度来源于FPGA
#define OTDR_POWER           (0x22)  // 作废：OTDR电源控制
#define OTDR_PULSE_ENCODE    (0x23)  // 作废：OTDR脉冲模式

/* OCVL 测试数据命令 */
#define OCVL_PARAM           (0x16)  // 震动定位

//#define OTDR_RD_REG             (0x24)  // TF500 对寄存器芯片进行读操作

#define OTDR_ALARM_APPEAR    (0x25)  // TMS400 告警输出 数码管显示
#define OTDR_ALARM_DISAPPEAR (0x26)  // TMS400 告警取消

#define OTDR_WD_REG          (0x27)  // TF500 对寄存器芯片进行写操作 2018-8-27
#define OTDR_RD_REG          (0x28)  // TF500 对寄存器芯片进行读操作 2018-8-27

#define OCID_PARAM           (0x30)
#define OCID_LEVEL           (0x31)
#define OCID_START           (0x32)
#define OCID_STOP            OTDR_STOP
#define OCID_READ_DATA       (0x33)

#define OCID_PARAM_LOSS      (0x35)
#define ROUTE_DETECT         (0x34)  // 路由探测，无参数
#define CMD_GPIO             (0X22)
#define CMD_MDIO             (0X23)


//*****************************************************************************
// End FPGA所有项目用到的命令编号
//*****************************************************************************


/** @defgroup fpga_interface
 * @{
 */

/**
 * @brief	fpga 设备描述
 */
struct fpga_dev
{
    int             fd;         ///< 设备FD，正常 fpga_open 后返回
    unsigned long   pid;        ///< 设备id，正常 fpga_open 后返回
    char           *desc;       ///< 设备描述，，正常 fpga_open 后返回
    unsigned long   checksum;   ///< OTDR 曲线数据校验值，fpga_otdr_isfinish返回
    unsigned long   cum_count;  ///< 累加次数
    unsigned long   mask_amp;   ///< amp 有效值掩码，fpga_test_param.hw_amp的取值范围
    unsigned long   mask_apd;   ///< apd 有效值掩码，fpga_test_param.hw_apd_vol的取值范围
    pthread_mutex_t mutex;      ///< 互斥锁
    // void *private;

    // 如下内容放入private
    unsigned long sample_freq;  ///< 采样频率选择，单位hz
    unsigned long adopt_pt;     ///< 采样点数，单位个
    unsigned char ch;
    char	 *otdr_cache;
};
struct fpga_info
{
    int hw_ver;    ///< 硬件版本
    int ch;        ///< 通道数
    int soft_ver;  ///< 软件版本
};
static inline unsigned long get_sample_rate(struct fpga_dev *dev)
{
    return (dev->sample_freq);
}
static inline unsigned long get_sample_num(struct fpga_dev *dev)
{
    return (dev->adopt_pt);
}
static inline unsigned long get_ch(struct fpga_dev *dev)
{
    return (dev->ch);
}
/**
 * @brief	otdr 测试参数
 * @remark	可以通过 @ref 构建默认测试参数 填充该项
 */
struct fpga_test_param
{
    /*!<
        OTDR 测试参数描述，与硬件无关

               <      1 / laser_freq   >
               <  pulse >
                --------                 --------
               |        |               |        |
               |        |               |        |
               |        |               |        |
            ---|        |---------------|        |------------

                ^ ^ ^ ^ ^ ^ ^ ^          ^ ^ ^ ^ ^ ^ ^ ^
                | | | | | | | |          | | | | | | | |
                       /   \
                      /     \
                    /         \
                  /             \
                 <1 / sample_freq>
    */
    bool          en_hw_dist;
    unsigned long dist;  /// 测试量程单位米，该字段内容决定采用什么采样率 fpga_test_param.sample_freq

    unsigned short laser_freq;  ///< 激光器脉冲频率选择
    bool           en_hw_pulse;
    unsigned short pulse; /*!< 脉冲宽度，单位ns*/


    unsigned short sample_freq;  ///< 采样频率选择，单位hz

    bool           en_hw_adopt_pt;
    unsigned long  adopt_pt;  ///< 采样点数，单位个
    bool           en_hw_add_cnt;
    unsigned short add_cnt;  ///< 累加次数，单位次
    bool           en_hw_add_ms;
    unsigned short add_ms;  ///< 累加时间，单位ms

    unsigned long amp; /*!< 使能放大： 1：使能放大开关，与具体放大倍数无关.
               但必须保证，各放大开关打开之后效果必定比前一个大\n

               运放级别分成3级，对应24bit \n
                00000000 00000000 00000000 00000000\n
               |..........................|=======| ----  1级放大\n
               |.................|=======|......... ----  2级放大\n
               |........|=======|.................. ----  3级放大\n
               |=======|...........................  ----  预留\n
                例子:\n\n
                00000000 00000000 00000011 00000001\n ---> 使能1级放大开关S1-1，使能2级放大S2-1、S2-2
               */
    bool en_hw_amp;
    char hw_amp;

    char apd_vol; /*!< APD电压，数值越高电压越高，@ref APD电压范围
          OTDR_APD_LOW~OTDR_APD_HIGH
          */
    bool en_hw_apd_vol;
    char hw_apd_vol;

    char power; /*!< 激光器功率，数值越高功率越高，@ref 光功率控制
            OTDR_LASER_PW_LOW ~ OTDR_LASER_PW_HIGH
            */

    char isrun;  ///< 是否启动


    short laser_ch; /*!< 激光器通道，从1开始计数，
            同时 “可能选择性” 支持以波长（单位nm）方式指定通道，
            如：1310、1550、1625。\n
            1 通道对应 1310nm 激光器\n
            2 通道对应 1550nm 激光器\n
            具体对应关系与接口实现有关
            */
    char panel_ch;  /*!< 面板光口通道，从 1 开始计数
            可能由光开关控制，同一面板通道可能不同时刻用于不同激光器通道
            */
#if defined(CONFIG_EN_CAP)
    unsigned long cap;        //  电容等级，描述值
    bool          en_hw_cap;  //  使能硬件编码
    char          hw_cap;     //  硬件编码
#endif
};


/*
- OCVL_PARAM 0x16： 震动定位项目中，发送OTDR_PARAM后需要发送此命令
- byte 1:延时纤模式:1或2
- byte 2：null

struct ocvl_param t_buf;
char r_buf[32]; // 这个不能舍去
t_buf.mode = 1;
fpga_send_data(
    dev, OCVL_PARAM,
    &t_buf, sizeof(struct ocvl_param),
    NULL, 0)
*/

struct ocvl_param
{
    char mode;
    char unuse;
} __attribute__((__packed__));

/*
新命令 0x35：OCID多发一个回损值
        - byte 1：10-60
        - byte 2：null
*/
struct ocid_param_loss
{
    char loss;
    char unuse;
} __attribute__((__packed__));


/*FPGA 发送数据通用格式*/
int fpga_send_data(
	struct fpga_dev *dev,
	char             cmd,
	void            *t_buf,
	int              tlen,
	void            *r_buf,
	int              rlen);

/*
- OCVL_PARAM 0x16： 震动定位项目中，发送OTDR_PARAM后需要发送此命令
- byte 1:延时纤模式:1或2
- byte 2：null

struct mdio_tx t_buf;
struct mdio_rx r_buf;
t_buf.mode = 1;
fpga_send_data(
    dev, OCVL_PARAM,
    &t_buf, sizeof(struct mdio_tx),
    &r_buf, sizeof(struct mdio_rx);
*/
#define MDIO_R 1
#define MDIO_W 2
struct mdio_tx
{
    char  option;  // 1读、2写
    char  phy;     // phy 5bit
    char  reg;     // reg 5bit
    short value;
} __attribute__((__packed__));
struct mdio_rx
{
    char  unuse[10];
    char  ack;
    char  unuse1[1];
    short value;
    short cksum;
} __attribute__((__packed__));


#define GPIO_R 1
#define GPIO_W 2
struct gpio_tx
{
    char option;  // 1读、2写
    char id;
    char value;
    char unuse;
} __attribute__((__packed__));
struct gpio_rx
{
    char  unuse[10];
    char  ack;
    char  unuse1[1];
    short value;
    short cksum;
} __attribute__((__packed__));

/** @defgroup 各量程脉冲列表
* @{
*
* 例如TP_PULSE_100KM_5120_NS与TP_PULSE_180KM_10240_NS对应的值均是128，但生成的
* 脉冲宽度不同，本质在于两100Km量程下采样始终25MHz，180Km量程12MHz

<table>
<tr><th>量程(km) <th>采样频率(MHz) 	<th>采样时间(ms)	<th>光往返时间(ms)	<th>脉冲周期(ms)	<th>1s内单个时钟对应的累加次数
<tr><td>1	<td>  800		<td>0.04		<td>0.01		<td>0.1 		<td>10000
<tr><td>5	<td>  400		<td>0.08		<td>0.05		<td>0.3125 		<td>3200
<tr><td>10	<td>  200		<td>0.16		<td>0.1			<td>0.5			<td>2000
<tr><td>30	<td>  100		<td>0.32		<td>0.3			<td>1 			<td>1000
<tr><td>60	<td>  50		<td>0.64		<td>0.6			<td>1			<td>1000
<tr><td>100	<td>  25		<td>1.28		<td>1			<td>2.666 		<td>375
<tr><td>200	<td>  12.5		<td>2.56		<td>2			<td>2.666		<td>375
</table>
*/
/** end 各量程脉冲列表
 * @}
 */


/** @defgroup FPGA导出接口
 * @{
 */


/**
 * @brief	打开OTDR采集卡，设备挂在SPI总线上
 * @param[in]	device 设备节点
 * @param[out]	dev 设备喵师傅
 * @param[in]	ispeed 指定通信速率，传递0时采用默认500KHz
 * @retval	0  成功 dev返回有效值
 * @retval	-1 设备节点打开失败
 * @retval	-2 设备打开成功，但检测不到FPGA
 * @see fpga_close
 */
int fpga_open(char *device, struct fpga_dev **dev, unsigned long ispeed);

/**
 * @brief	关闭已打开的otdr采集卡
 * @param[in]	dev 设备描述符
 * @retval	null
 * @see fpga_open
 */
int fpga_close(struct fpga_dev *dev);

/**
 * @brief	otdr测试开始
 * @param[in]	dev 设备描述符
 * @retval	null
 * @remarks	之前必须先保证调用 @ref fpga_otdr_param 配置有效值，如果参数每变化
    之后可连续调用 	fpga_otdr_start
 * @see	fpga_otdr_param
 */
int fpga_otdr_start(struct fpga_dev *dev);
/**
 * @brief	无论当前测试是否已经启动，停止OTDR测试
 * @param[in]	dev 设备描述符
 * @remarks
 * @see
 */

int fpga_otdr_stop(struct fpga_dev *dev);
/**
 * @brief	询问OTDR是否已经完成一组测试，完成则记录数据的校验值，
        校验值存储在 fpga_dev.checksum 应用程序无需处理。\n
        完成时间长短由 @ref fpga_otdr_param
        配置参数 fpga_test_param.adopt_pt ， fpga_test_param.add_cnt 决定，
        数值越大完成一组测试时间越久
 * @param[in]			dev 设备描述符
 * @param[in][out]		isfinish 完成状态
 * @retval	0 通信正常
    isfinish=true 准备完毕
    isfinish=false 忙碌
 * @retval	-1 通信错误
 * @remarks	保证之前已经启动测试 @ref fpga_otdr_start，在无测试情况下永远返回完成
 * @see fpga_otdr_start
 */

int fpga_otdr_isfinish(struct fpga_dev *dev, bool *isfinish);

/**
 * @brief	读取OTDR温度
 * @param	val 温度值被扩大100倍，50.23℃ -> 50230
 * @retval	null
 * @remarks
 * @see
 */
int fpga_otdr_temp(struct fpga_dev *dev, int *val);


/** @defgroup 运放控制
 * @{
 */

#define TP_AMP_L1(n)       ((n)&0xff)          ///< 运放1级放大  参考 struct fpga_test_param.amp
#define TP_AMP_L2(n)       (((n)&0xff) << 8)   ///< 运放2级放大  参考 struct fpga_test_param.amp
#define TP_AMP_L3(n)       (((n)&0xff) << 16)  ///< 运放3级放大  参考 struct fpga_test_param.amp
#define TP_AMP_L4(n)       (((n)&0xff) << 24)  ///< 运放4级放大 参考 struct fpga_test_param.amp
/** end 运放控制
 * @}
 */


/** @defgroup APD电压范围
 * @{
 */
#define TP_APD_39V         (39)  ///< APD 39V
#define TP_APD_30V         (30)  ///< APD 30V
#define OTDR_APD_HIGH      TP_APD_39V
#define OTDR_APD_LOW       TP_APD_30V
/** end APD电压范围
 * @}
 */


/** @defgroup 光功率控制
 * @{
 */
#define OTDR_LASER_PW_LV1  1                  ///< 激光器功率 Level1 最小功率
#define OTDR_LASER_PW_LV2  2                  ///< 激光器功率 Level2
#define OTDR_LASER_PW_LV3  3                  ///< 激光器功率 Level3
#define OTDR_LASER_PW_LV4  4                  ///< 激光器功率 Level4 最大功率
#define OTDR_LASER_PW_HIGH OTDR_LASER_PW_LV4  ///< 激光器功率 最大功率
#define OTDR_LASER_PW_LOW  OTDR_LASER_PW_LV1  ///< 激光器功率 最大功率
/** end 光功率控制
 * @}
 */


/**
 * @brief	设置OTDR测试参数，设置之后应该有10ms延时，等待光耦开关稳定
        才能执行 @ref fpga_otdr_start 测试，如果两次调用 fpga_otdr_param
        之间没有调用 fpga_exist_com_laser 则不延时
 * @param[in]	dev 设备描述符
 * @param[in]	val 所有参数采用自然编码，具体参数意义参考 struct fpga_test_param
 * @retval	null
 * @remarks @ref fpga_exist_com_laser 无视当前测试参数，自动切换测试量程，
    所以每次检查通信光状态后都应该重新设置测试参数
 * @see fpga_otdr_start
 * @see fpga_exist_com_laser
 * @see	_encode_laser  @see _encode_adopt  @see _encode_add_cnt
 * @see _encode_power  @see _encode_amp  @see _encode_apd_vol
 * @see _encode_slot  @see _encode_ch
 */
int fpga_otdr_param(struct fpga_dev *dev, struct fpga_test_param *val);
/**
 * @brief	请求测试并等待一组测试数据准备完好后返回
        等同于 @ref fpga_otdr_param ~ @ref fpga_otdr_isfinish 之间的所有调用
 * @param[in]	dev 设备描述符
 * @param[in]	val 测试参数
 *		默认各量程测试参数填充 @ref 构建默认测试参数 可在默认基础上做修改
 * @retval	0 数据准备完好
 * @retval	-1 通信失败或等待数据超时间
 * @see fpga_otdr_param
 * @see fpga_otdr_isfinish
 */
int fpga_request_test(struct fpga_dev *dev, struct fpga_test_param *val);


/** @defgroup 红光模式
 * @{
 */
#define OTDR_RL_OFF  (0)  ///< 关闭红光
#define OTDR_RL_ON   (1)  ///< 红光常亮 1.2ms高电平，3.7ms低电平
#define OTDR_RL_1HZ  (2)
#define OTDR_RL_10HZ (3)
#define OTDR_RL_SLOW OTDR_RL_1HZ   ///< 红光慢闪烁 1HZ 500ms高电平，500ms低电平
#define OTDR_RL_FAST OTDR_RL_10HZ  ///< 红光快闪烁 10HZ 100ms高电平，100ms低电平
/** end 红光模式
 * @}
 */

/**
 * @brief	红光输出控制
 * @param[in]	dev 设备描述符
 * @param[in]	val 红光模式
 *		模式选择范围 @ref 红光模式
 * @retval	null
 */
int fpga_red_laser(struct fpga_dev *dev, int mode);

/**
 * brief	调节LCD背光
 * @param[in]	dev 设备描述符
 * @param[in]	val lcd 背光输出频率
 * @retval	null
 * @remarks
 * @see
 */
int fpga_lcd_bl(struct fpga_dev *dev, int val);

/**
 * @brief	获取电池状态
 * @param[in]	dev 设备描述符
 * @param[in]	status 状态
 * @retval	null
 * @remarks
 * @see
 */
int fpga_charge_status(struct fpga_dev *dev, char *status);

/** @defgroup 低功耗模式
 * @{
 */
#define OTDR_LOW_POWER (0) /*!< 低功耗 */
#define OTDR_OFF_POWER (1) /*!< 关闭电源，此电源是处理器总电源，如果存在ARM与FPGA同时控制该电源， \
                                        则先FPGA关断，后ARM关断*/
/** end 低功耗模式
 * @}
 */

/**
 * @brief	fpga电源模式
 * @param[in]	dev 设备描述符
 * @param[out]	mode 选择电源模式
 *		模式选择范围 @ref 低功耗模式
 * @retval	null
 * @remarks	该命令FPGA没有返回值，永远认为成功
 * 		当选择关闭电源模式OTDR_OFF_POWER时，处理器端必须保证其数据安全保存
 */
int fpga_low_power(struct fpga_dev *dev, int mode);

/**
 * @brief	通信光检测
 * @param[in]	dev 设备描述符
 * @param[out]	status 光路通信状态
 * @retval	0 通信正常
    isexist=true 存在通信光
    isexist=false 不存在通信光
 * @retval	-1 通信错误
 * @remarks
 */
int fpga_exist_com_laser(struct fpga_dev *dev, bool *isexist);

/**
 * @brief	读取FPGA软硬件版本号
 * @param[in]	dev 设备描述符
 * @param[out]	soft_ver 表示该软件所能支持的硬件版本
 * @param[out]	hw_ver 硬件外围器件特性，可随时根据生产而修改，读取的是电路板上
        拨码开关或固定电阻
 * @retval	0 通信正常
 * @retval	-1 通信错误
 * @remarks	有待定义软硬件版本具体描述
 */

int fpga_version(struct fpga_dev *dev, char *soft_ver, char *hw_ver);
int fpga_info(struct fpga_dev *dev, struct fpga_info *out);


/**
 * @brief	读取OTDR所有数据，并计算校验值是否匹配\n
        向FPGA发送读取指令，@ref _read_otdr_first \n
        若干次调用 @ref _read_otdr_serial 读取余下若干帧
 * @param	otdr_data 存储OTDR数据点，每个点以4byte存储
 * @param	len otdr_data 存储长度，必须是 32000* 4、64000*4、128000*4之一
 * @retval 0 通信正常校验值比对成功
 * @retval -1 通信正常校验值比对失败，通信错误
 * @remarks	读取前必须保证数据已经准备好 @ref fpga_otdr_isfinish ，
    发送方的正确校验码在 fpga_otdr_isfinish 里传输，无论校验正确与否
    otda_data 都被修改
 * @bug 1. 整个 fpga_read_otdr_data 必须独占总线，未完成前总线被其他对象占用
    都讲导致数据错误（该缺陷由通信协议确定）

 * @bug 2. 如果读取曲线发生校验码错误，则必须重新测试
    （fpga_otdr_start - fpga_otdr_isfinish - fpga_read_otdr_data）。
    在不重测情况下，多次调用fpga_read_otdr_data永远校验错误。
 * @see	fpga_otdr_isfinish
 * @see _otdr_data_swap
 * @see _otdr_checksum
 * @see _read_otdr_first
 * @see _read_otdr_serial
 */

int fpga_read_otdr_data(
	struct fpga_dev *dev,
	unsigned char   *otdr_data,
	unsigned long    len);

/**
 * @brief	调试光耦开关，被选定的开关变成高电平，“同功能开关”的其余开关变成低电平，
        其余开关的状态是它收到控制器发送 00 的结果，具体开关高电平有效还是
        低电平有效由硬件而定。\n
    何为同功能开关：\n
        amp 与 apd 都是用光耦开关控制，各有若干开关。若：\n
        amp有6个开关，分别对应S1-S6，属于同功能开关\n
        apd有3个开关，分别对应S7-S9，属于另一同功能开关\n
        当sw_index=1 时，表示 S1 为高电平，S2-S6为低电平，至于S7-S9状态不做控制，
        同理设置sw_index=7时, 表示 S7 为高电平，S8-S9为低电平，至于S1-S6状态不做控制，

 * @param[in]	dev 设备描述符
 * @param[in]	param 所有参数采用自然编码，具体参数意义参考 struct fpga_test_param
 * @param[in]	sw_index 唯一使能的光耦开关，使能后高电平
 * @retval 0 通信正常校验值比对成功
 * @retval -1 通信正常校验值比对失败，通信错误
 */
unsigned long fpga_dbg_sw(struct fpga_dev *dev, struct fpga_test_param *param, int sw_index);

/**
 * @brief	检测FPGA是否存在，心跳
 * @param[in]	dev 设备描述符
 * @retval	0 存在
 * @retval	-1 不存在，或总线错误
 * @remarks	fpga_open 里自动调用它
 */

unsigned int fpga_alive(struct fpga_dev *dev);


/**
 * @brief	FPGA电源
 * @param	val 1 打开，0关闭
 */
int fpga_power(struct fpga_dev *dev, int val);


/**
 * @brief	调制脉冲编码
 * @param	val 脉冲开关
 * 			val 长度16Byte、128bit，没用的字节用0补全
 *			如val序列是
 *          0byte  1byte  2byte  3byte      15byte
 *          0xf0   0xe0    0xc1   0x00 .... 0x00
 *         当bit为1时，激光器发光，否则关闭，脉冲宽度由 fpga_otdr_param 指定
 *
 * char val[16] = {0xf0, 0xe0, 0xc1};
 * fpga_pulse(dev, &val);
 */

int fpga_pulse(struct fpga_dev *dev, char (*val)[OTDR_PULSE_ARRAY]);


/** end 构建默认测试参数
 * @}
 */

/** end FPGA导出接口
 * @}
 */


/** end fpga_interface
 * @}
 */


//*****************************************************************************

/** @defgroup fpga_ocid
 * @{
 */

struct fpga_ocid_test_param
{
    int ch;
    int post;       // 位置（由FPGA自己决定起始、结束位置）
    int post_from;  // 起始位置（由ARM处理器决定两位置）
    int post_to;    // 结束位置（由ARM处理器决定两位置）

    int sensitive;  // FPGA对数据的灵敏度（或者成为电压值、音量值）
                    // TODO
};


/**
 * @brief	设置OCID测试参数
 * @param	val 具体struct fpga_ocid_test_param里面的内容有待商妥，
------------------可能吧 测试灵敏度也放在里面------------------
 * @retval	0 通信正常
 * @retval	-1 通信错误
 */

int fpga_ocid_param(struct fpga_dev *dev, struct fpga_ocid_test_param *val);


/**
 * @brief	设置灵敏度    （可能作废）
 * @param	null
 * @retval	null
 * @remarks
 * @see
 */

int fpga_ocid_sensitive(struct fpga_dev *dev, int sensitive);
/**
 * @brief	读取OCID音频数据
 * @param	ocid_data 有效数据是每个数据点16bit，
 * @param	len 希望读取的数据点数，ocid_data必须比ocid_data大
 * @param	rlen 实际读取到的数据点
 * @retval	0 通信正常
 * @retval	-1 通信错误
 * @remarks	FPGA传输的数据格式
    23 00 bb cc 			第1个数据
    23 00 bb cc  			第2个数据
    23 00 bb cc  			第3个数据
    ...
    23 00 bb cc  			第N个数据
    00 00 00 00  			无用数据
    00 00 00 00   			无用数据
    其中n不大于512，
    fpga_read_ocid_data会去除后面的无用数据，计算总长度通过rlen返回
    并将最高字节（标志）0x23设置成0
 * @see
 */

int fpga_read_ocid_data(
	struct fpga_dev *dev,
	unsigned int    *ocid_data,
	unsigned long    len,
	unsigned long   *rlen);
/**
 * @brief	启动测试
 * @param	null
 * @retval	0 通信正常
 * @retval	-1 通信错误
 * @remarks
 * @see
 */

int fpga_ocid_start(struct fpga_dev *dev);
/**
 * @brief	结束OCID测试
 * @param	null
 * @retval	0 通信正常
 * @retval	-1 通信错误
 * @remarks	无论是否启动测试，FPGA都必须应答该命令
 * @see
 */

int fpga_ocid_stop(struct fpga_dev *dev);

/**
 * @brief	向FPGA发送告警
 * @param	ch OCID、TMS400通道号
 * @param	is_appear 1 发现告警，0告警取消
 * @retval	0 通信正常
 * @retval	-1 通信错误
 * @see
 */
int               fpga_alarm(struct fpga_dev *dev, int ch, int is_appear);
static inline int fpga_cum_count(struct fpga_dev *dev)
{
    return dev->cum_count;
}
/** end fpga_ocid
 * @}
 */

int  fpga_wd_reg(struct fpga_dev *dev, char *data);
int  fpga_rd_reg(struct fpga_dev *dev, char *data);
void fpga_update_env();


int fpga_ocvl_start(struct fpga_dev *dev);
int fpga_read_ocvl_data(
	struct fpga_dev *dev,
	unsigned char   *otdr_data,
	unsigned long    len);
int  fpga_ocvl_param(struct fpga_dev *dev, struct fpga_test_param *val);
int  fpga_ocvl_isfinish(struct fpga_dev *dev, bool *val);
void fpga_save_32bit(char *fname, unsigned char *data, unsigned long len);

#ifdef __cplusplus
}
#endif


#endif
